<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <h3 v-html="msg"></h3>
        <h3 v-html="msg"></h3>
        <h3 v-html="msg"></h3>
        <input type="text" v-model="msg">
    </div>
    <script>
        class Watcher {
          constructor () {
            this.steward = {}
          }
        }
        Watcher.prototype.$on = function (eventName, listener) {
          if(this.steward[eventName]) {
            this.steward[eventName].push(listener)
          } else {
            this.steward[eventName] = [listener]
          }
        }
        Watcher.prototype.$emit = function(eventName) {
            if (this.steward[eventName]){
                this.steward[eventName].forEach(fn => fn())
            }
        }
        const watcher = new Watcher()
        class Vue {
          constructor (options) {
            const { el, created, ...option } = options
            const app = document.querySelector(el)
            this.$el = app
            this.obServer(option)
            created && created.apply(this)
            this.compile()
          }
          obServer (option) {
            Object.keys(option)
            .filter(item => typeof option[item] === 'object' && typeof option[item] !== 'function')
            .map(keys => {
                for (let key in option[keys]) {
                  Object.defineProperty(this, key, {
                    get () {
                      console.log('getter')
                      return option[keys][key]
                    },
                    set (newVal) {
                      option[keys][key] = newVal
                      watcher.$emit(key)
                    }
                  })
                }
            })
            // for (let key in option) {
            //   if (typeof option[key] === 'object' && typeof option[key] !== 'function' && !Array.isArray(option[key])) {
            //     //   console.log(key)
            //     this.obServer(option[key])
            //   } else {
            //     Object.defineProperty(this, key, {
            //       get () {
            //         console.log('使用get')
            //         return option[key]
            //       }
            //     });
            //     // console.log(this.$el);
            //   }
            // }
          }
          compile () {
            [...this.$el.children].forEach(node => {
              if (node.hasAttribute('v-html')) {
                let key = node.getAttribute('v-html')
                node.innerHTML = this[key]
                watcher.$on(key, () => {
                  node.innerHTML = this[key]
                })
              }
            });
            [...this.$el.children].forEach(node => {
              if (node.hasAttribute('v-model')) {
                let key = node.getAttribute('v-model')
                node.value = this[key]
                watcher.$on(key, () => {
                  node.value = this[key]
                })
                node.addEventListener('input', () => {
                  this[key] = node.value
                })
              }
            })
          }
        }
        const vm = new Vue({
          el: '#app',
          data: {
            msg: 5000
          },
          methods: {
            change () {
              console.log('change')
            }
          }, 
          computed: {
            cUserName () {
              return 'berlin'
            }
          },
          created () {
            console.log('created')
            console.log('cr', this.msg);
          }
        })
        console.log(vm.msg);
    </script>
</body>
</html>